#region LGPL Header
// Copyright (C) 2009, Jackie Ng
// http://code.google.com/p/fdotoolbox-addins, jumpinjackie@gmail.com
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
// 
//
// See license.txt for more/additional licensing information
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using FdoToolbox.Base.Controls;
using FdoToolbox.AddIns.MapGuide.Services;
using FdoToolbox.Base.Services;
using System.Windows.Forms;
using ICSharpCode.Core;
using OSGeo.MapGuide.MaestroAPI;

namespace FdoToolbox.AddIns.MapGuide.Controls
{
    public class MapGuideObjectExplorerExtender : IObjectExplorerExtender
    {
        private string RootNodeName = "NODE_MG_CONNECTIONS";

        const string NODE_MG_CONNECTION = "NODE_MG_CONNECTION";
        const string NODE_MG_FEATURESOURCE = "NODE_MG_FEATURESOURCE";

        const string PATH_MG_CONNECTIONS = "/ObjectExplorer/ContextMenus/MapGuideConnections";
        const string PATH_SELECTED_CONNECTION = "/ObjectExplorer/ContextMenus/SelectedMgConnection";
        const string PATH_SELECTED_FEATURESOURCE = "/ObjectExplorer/ContextMenus/SelectedMgFeatureSource";

        private IObjectExplorer _explorer;
        private MgConnectionManager _connMgr;

        const string IMG_SERVER = "server";
        const string IMG_SERVER_CONNECTION = "server_connect";
        const string IMG_SERVER_DATABASE = "server_database";

        public void Decorate(IObjectExplorer explorer)
        {
            _explorer = explorer;
            _connMgr = ServiceManager.Instance.GetService<MgConnectionManager>();
            _connMgr.ObjectAdded += new ManagerObjectEventHandler(OnConnectionAdded);
            _connMgr.ObjectRemoved += new ManagerObjectEventHandler(OnConnectionRemoved);
            _connMgr.ObjectRenamed += new ManagerObjectRenamedEventHandler(OnConnectionRenamed);

            _explorer.RegisterImage(IMG_SERVER);
            _explorer.RegisterImage(IMG_SERVER_CONNECTION);
            _explorer.RegisterImage(IMG_SERVER_DATABASE);

            _explorer.RegisterRootNode(RootNodeName, ResourceService.GetString("MG_CONNECTIONS"), IMG_SERVER_CONNECTION, PATH_MG_CONNECTIONS);
            _explorer.RegisterContextMenu(NODE_MG_CONNECTION, PATH_SELECTED_CONNECTION);
            _explorer.RegisterContextMenu(NODE_MG_FEATURESOURCE, PATH_SELECTED_FEATURESOURCE);
        }

        void OnConnectionRenamed(object sender, ManagerObjectRenameArgs e)
        {
            TreeNode node = _explorer.GetRootNode(RootNodeName).Nodes[e.OldName];
            node.Name = node.Text = e.NewName;
        }

        void OnConnectionRemoved(object sender, FdoToolbox.Core.EventArgs<string> e)
        {
            _explorer.GetRootNode(RootNodeName).Nodes.RemoveByKey(e.Data);
            LoggingService.Info(string.Format("Connection removed: {0}", e.Data));
        }

        void OnConnectionAdded(object sender, FdoToolbox.Core.EventArgs<string> e)
        {
            string name = e.Data;

            TreeNode node = CreateConnectionNode(name); 
            TreeNode root = _explorer.GetRootNode(RootNodeName);
            root.Nodes.Add(node);
            node.Expand();
            root.Expand();

            LoggingService.Info(string.Format("Connection added: {0}", e.Data));
        }

        private System.Windows.Forms.TreeNode CreateConnectionNode(string host)
        {
            ServerConnectionI conn = _connMgr.Get(host.ToString());
            System.Windows.Forms.TreeNode connNode = new System.Windows.Forms.TreeNode();
            connNode.Name = host;
            connNode.Text = conn.DisplayName;
            connNode.Tag = host;
            connNode.SelectedImageKey = connNode.ImageKey = IMG_SERVER_CONNECTION;
            connNode.ContextMenuStrip = _explorer.GetContextMenu(NODE_MG_CONNECTION);
            connNode.ToolTipText = string.Format("{0}\n\nVersion: {1}", conn.DisplayName, conn.SiteVersion);
            PopulateFeatureSources(connNode, conn);
            return connNode;
        }

        private void PopulateFeatureSources(System.Windows.Forms.TreeNode connNode, ServerConnectionI conn)
        {
            ResourceList featureSources = conn.GetRepositoryResources("Library://", "FeatureSource");
            connNode.Nodes.Clear();
            foreach (object res in featureSources.Items)
            {
                ResourceListResourceDocument doc = res as ResourceListResourceDocument;
                System.Windows.Forms.TreeNode fsNode = new System.Windows.Forms.TreeNode();
                fsNode.Text = doc.ResourceId;
                fsNode.Name = doc.ResourceId;
                fsNode.Tag = doc;
                fsNode.ImageKey = fsNode.SelectedImageKey = IMG_SERVER_DATABASE;
                fsNode.ToolTipText = doc.ResourceId;
                fsNode.ContextMenuStrip = _explorer.GetContextMenu(NODE_MG_FEATURESOURCE);
                try
                {
                    PopulateSchemaNodes(fsNode, conn);
                    connNode.Nodes.Add(fsNode);
                }
                catch
                {
                    //TODO: Log this error
                }
            }
        }

        private void PopulateSchemaNodes(System.Windows.Forms.TreeNode fsNode, ServerConnectionI conn)
        {
            FeatureSourceDescription desc = conn.DescribeFeatureSource(fsNode.Name);
            Dictionary<string, List<FeatureSourceDescription.FeatureSourceSchema>> classes = new Dictionary<string, List<FeatureSourceDescription.FeatureSourceSchema>>();
            foreach (FeatureSourceDescription.FeatureSourceSchema schema in desc.Schemas)
            {
                if (!classes.ContainsKey(schema.Schema))
                    classes[schema.Schema] = new List<FeatureSourceDescription.FeatureSourceSchema>();

                classes[schema.Schema].Add(schema);
            }

            foreach (string schema in classes.Keys)
            {
                System.Windows.Forms.TreeNode schemaNode = new System.Windows.Forms.TreeNode();
                schemaNode.Text = schemaNode.Name = schema;
                schemaNode.ToolTipText = schema;
                schemaNode.SelectedImageKey = schemaNode.ImageKey = "database";
                List<FeatureSourceDescription.FeatureSourceSchema> klasses = classes[schema];

                foreach (FeatureSourceDescription.FeatureSourceSchema klass in klasses)
                {
                    System.Windows.Forms.TreeNode classNode = new System.Windows.Forms.TreeNode();
                    classNode.Text = classNode.Name = klass.Name;
                    classNode.ToolTipText = klass.Name;
                    classNode.ImageKey = classNode.SelectedImageKey = "table";
                    PopulatePropertyNodes(classNode, klass.Columns);
                    schemaNode.Nodes.Add(classNode);
                }

                fsNode.Nodes.Add(schemaNode);
            }
        }

        private void PopulatePropertyNodes(System.Windows.Forms.TreeNode classNode, FeatureSetColumn[] properties)
        {
            foreach (FeatureSetColumn prop in properties)
            {
                System.Windows.Forms.TreeNode propNode = new System.Windows.Forms.TreeNode();
                propNode.Text = propNode.Name = prop.Name;
                propNode.ToolTipText = prop.Name;
                propNode.SelectedImageKey = propNode.ImageKey = "table";
                classNode.Nodes.Add(propNode);
            }
        }
    }
}
